/*
 *
 * File Name: dbus_client.c
 * Author: liaoxuecheng
 * mail: liaoxuecheng@hotmail.com
 * Created Time: 2024年12月25日 星期三 14时29分26秒
 *
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <dbus/dbus.h>

#include "at_dbus.h"
#include "tests.h"

#define THIS_FILE "dbus_client.c"

#ifndef PJ_LOG
#define TEST_PRINTF(title,fmt,arg...) printf("%s:%d %s, "fmt, __func__, __LINE__, title, ##arg)
#define PJ_LOG(arg, fmt) printf("level = %d, ",arg);TEST_PRINTF fmt;
#endif

static DBusHandlerResult handle_test_signal(DBusConnection *connection, DBusMessage *message)
{
    int ret_i;
    char *ret_s;
    unsigned int ret_u;
    double ret_d;
    at_variant *variant;

    variant = get_variant_from_message(message);
    if(variant == NULL) {
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    }
    at_variant_get(variant, "isud", &ret_i, &ret_s, &ret_u, &ret_d);
    PJ_LOG(4, (THIS_FILE, "Receive test signal:%d, %s, %u, %lf\n", ret_i, ret_s, ret_u, ret_d));
    at_variant_free(variant);
    return DBUS_HANDLER_RESULT_HANDLED;
}

static void path_unregistered_func(DBusConnection *connection, void *user_data)
{
    /* connection was finalized */
}

static DBusHandlerResult path_message_func(DBusConnection *connection, DBusMessage *message, void *user_data)
{
    if(dbus_message_is_signal(message, SERVER_OBJ_INTERFACE, "signal_test")) {
        return handle_test_signal(connection, message);
    }
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}

static DBusObjectPathVTable echo_vtable = {
    path_unregistered_func,
    path_message_func,
    NULL,
};

static DBusHandlerResult filter_func(DBusConnection *connection, DBusMessage *message, void *user_data)
{
    if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected"))
    {
        return DBUS_HANDLER_RESULT_HANDLED;
    }
    else
    {
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    }
}

void *dbus_main_loop_func(void *arg)
{
    dbus_threads_init_default();
    int ret = 0;
    void *d = NULL;
    DBusError error;
    DBusConnection *connection;
    dbus_error_init (&error);

    /* dbus_bus_get_private 只能注册signal信号 无法注册method信号 */
    connection = dbus_bus_get(DBUS_BUS_SESSION, &error);
    if(connection == NULL)
    {
        PJ_LOG(1, (THIS_FILE, "Failed to open connection: %s\n", error.message));
        dbus_error_free (&error);
        exit(0);
        return NULL;
    }

    ret = dbus_bus_request_name(connection, CLIENT_OBJ_NAME, 0, &error);
    if(dbus_error_is_set(&error))
    {
        PJ_LOG(1, (THIS_FILE, "Failed request bus name: %s\n", error.message));
        dbus_error_free (&error);
        exit(1);
    }

    if(ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
    {
        PJ_LOG(1, (THIS_FILE, "Unable to acquire service: code %d\n", ret));
        //exit(1);
    }

    if(!dbus_connection_add_filter (connection, filter_func, NULL, NULL))
    {
        PJ_LOG(1, (THIS_FILE, "No memory"));
        exit(1);
    }

    if(!dbus_connection_register_object_path (connection, SERVER_OBJ_PATH, &echo_vtable, (void*) 0xdeadbeef))
    {
        PJ_LOG(1, (THIS_FILE, "No memory"));
        exit(1);
    }

    if (!dbus_connection_get_object_path_data (connection, SERVER_OBJ_PATH, &d))
    {
        PJ_LOG(1, (THIS_FILE, "No memory"));
        exit(1);
    }
    if (d != (void*)0xdeadbeef)
    {
        PJ_LOG(1, (THIS_FILE, "dbus_connection_get_object_path_data() doesn't seem to work right\n"));
        exit(1);
    }

    at_dbus_add_signal_match(connection, SERVER_OBJ_NAME);
    dbus_connection_flush(connection);

    simple_loop(connection);

    while(dbus_connection_read_write_dispatch (connection, 1))
    {
        usleep(1000);
    }

    dbus_connection_remove_filter (connection, filter_func, NULL);
#if 0
    /* dbus_bus_get_private need colse frist */
    dbus_connection_close(connection);
#endif
    dbus_connection_unref (connection);
    return 0;
}

int test_dbus_send_method_call(at_proxy *test_proxy)
{
    DBusConnection *conn;
    DBusError error;
    at_variant *variant = NULL, *reply = NULL;
    char *recv_mesg = NULL;

    dbus_error_init (&error);
    conn = dbus_bus_get(DBUS_BUS_SESSION, &error);
    if(conn == NULL)
    {
        PJ_LOG(1, (THIS_FILE, "Failed to open connection: %s\n", error.message));
        dbus_error_free(&error);
        return 1;
    }

    variant = at_variant_new("s", "hello server!");
    if(variant == NULL)
    {
        PJ_LOG(1, (THIS_FILE, "No memory\n"));
        exit(1);
    }

    PJ_LOG(1, (THIS_FILE, "recv_mesg: %s\n", recv_mesg));
    reply = at_dbus_call_sync(conn, test_proxy, "Echo", variant, &error);
    if(reply == NULL && dbus_error_is_set(&error))
    {
        PJ_LOG(1, (THIS_FILE, "method call error: %s\n", error.message));
        dbus_error_free(&error);
        goto ERR;
    }

    at_variant_get(reply, "s", &recv_mesg);
    PJ_LOG(1, (THIS_FILE, "recv_mesg: %s\n", recv_mesg));

    at_variant_free(reply);
    at_variant_free(variant);
    dbus_connection_unref(conn);
    return 0;
ERR:
    at_variant_free(reply);
    at_variant_free(variant);
    dbus_connection_unref(conn);
    return -1;
}

void *dbus_main(void *arg)
{
    int i = 10000;
    pthread_detach(pthread_self());
}

int main(int argc, char **argv) 
{
    pthread_t thread;
    at_proxy *test_proxy;
    static pthread_mutex_t mute = {0};
    dbus_threads_init_default();
    at_dbus_init_common_connection(&mute, 0);
    init_args(argc, argv);

    test_proxy = at_proxy_new(SERVER_OBJ_NAME, SERVER_OBJ_PATH, SERVER_OBJ_INTERFACE);
    if(test_proxy == NULL)
    {
        PJ_LOG(1, (THIS_FILE, "Failed to create proxy error\n"));
        exit(1);
    }

    pthread_create(&thread, NULL, dbus_main_loop_func, NULL);

    test_method_and_signal_random();

    while(1)
    {
        sleep(4);
        test_dbus_send_method_call(test_proxy);
    }

    at_proxy_free(test_proxy);
    return 0;
}
